
/***************************************************************************
 *   fecab 
 *                                                                         *
 *   Copyright (C) 2010 by kuerant                                         *
 *                         <kuerant@gmail.com>                             *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This library is distributed in the hope that it will be usefull, but  *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   Library General Public License for more details.                      *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston,                *
 *   MA 02111-1307, USA                                                    *
 ***************************************************************************/

#include <list>
#include <string>

#include <boost/thread/mutex.hpp>

#include <db_cxx.h>

#include "bocat/common/lrucache.hpp"

#include "fecab/store.hpp"


namespace	fecab	{


struct	SleepyConfig
{
public	:
	std::string	envhome;		// path to environment home
	std::string	engine;			// engine type, default : btree
	std::string	dbfile;			// path to db file, default : sleepy.db

	u_int32_t	ntables;		// number of table to store data, default : 65536
	u_int32_t	btree_minkey;	// minkey option for BTree engine, default : 0

	u_int32_t	ncache_tables;	// number of table handle in cache, default : 1024

	bool		in_recovery;
public	:
	SleepyConfig( const char* config_filename );

private :
	#define	INI_SECTION		"fecab::store"
	#define	DEFAULT_DB_FILENAME	"sleepy.db"
	#define	DEFAULT_ENGINE	"btree"
	#define	DEFAULT_NTABLES	256
	#define	DEFAULT_NCACHE_TABLES	1024

	int		parseConfig( const char* config_filename );
};	//// class SleepyConfig


///////////////////////////////////////////////////////////////////////
//  class SleepyStore
//

class	SleepyStore
		:	public Store
{

public  :
	SleepyStore( const char* config_filename );

    virtual ~SleepyStore(); 

public  :

    virtual int     put( std::string table,
                         const char* key,    u_int32_t key_size,
                         const char* data,   u_int32_t data_size );

    virtual int     put( const char* table,
                         const char* key,    u_int32_t key_size,
                         const char* data,   u_int32_t data_size );

    virtual int     put( u_int32_t   pin,
                         const char* key,    u_int32_t key_size,
                         const char* data,   u_int32_t data_size );

    virtual int     get( std::string table,
                         const char* key,    u_int32_t key_size,
                         const char* buf,    u_int32_t buf_size );

    virtual int     get( const char* table,
                         const char* key,    u_int32_t key_size,
                         const char* buf,    u_int32_t buf_size );

    virtual int     get( u_int32_t   pin,
                         const char* key,    u_int32_t key_size,
                         const char* buf,    u_int32_t buf_size );

    virtual int     erase( std::string table,
                           const char* key,    u_int32_t key_size );

    virtual int     erase( const char* table,
                           const char* key,    u_int32_t key_size );

    virtual int     erase( u_int32_t   pin,
                           const char* key,    u_int32_t key_size );

public  :


    virtual int     put( const std::string& table,
                         const std::string& key,    
                         const std::string& data );

    virtual int     put( u_int32_t   pin,
                         const std::string& key,
                         const std::string& data );

    virtual int     get( const std::string& table,
                         const std::string& key,
                               std::string& buf );

    virtual int     get( u_int32_t   pin,
                         const std::string& key,
                               std::string& buf );

    virtual int     erase( const std::string& table,
                           const std::string& key );

    virtual int     erase( u_int32_t   pin,
                           const std::string& key );


private	:
	std::string		getTableName( u_int32_t pin );
	u_int32_t		getTableId( u_int32_t pin );

private	:

	SleepyConfig	config;

private	:
	DbEnv*	dbenv_p;

	void	recoverDbEnv();
	void	openDbEnv();
	void	closeDbEnv();

	void	createDefaultDbConfig( const std::string filename );


private :
	typedef	Db *	dbp_type;
	typedef	std::list< dbp_type >	list_dbp_type;

	list_dbp_type	free_dbp_list;
	boost::mutex	free_dbp_list_mutex;

	// get dbp from free_dbp_list, or create a new one
	dbp_type	getDbp();
	// release dbp, and put it on free_dbp_list
	void		freeDbp( dbp_type& );
	// free all dbp_type in  free_dbp_list
	void		purgeDbp();

private	:
	typedef	bocat::common::LRUCache< std::string, dbp_type >	dbp_cache_type;

	dbp_cache_type	dbp_cache;
	boost::mutex	dbp_cache_mutex;

	dbp_type	openTable( const std::string& table_name );
	void		closeAllTables();

private	:
	u_int32_t	_count_put_or_erase;

	char*		_dbt_data_buf_p;
	u_int32_t	_dbt_data_buf_size;
	boost::mutex	_dbt_data_buf_mutex;

};	//// class SleepyStore



}	//// namespace fecab

